import { Asset, AudioSource, error, find, SpriteRenderer, Node, AudioClip, director } from "cc";

export class SpecialResMgr {
    //作为各种具体资源管理者的基类，包括各管理者的公共属性和方法

    //创建自己的资源容器，用来存储对应类型的资源。，因为需要被子类继承，而类的外部不能获取，故使用protected
    //类型为Asset：因为Asset是Prefab,Spriteframe等所有资源类型的基类，在此无法确定具体资源类型，只能写它们的公共类型
    protected _mapRes: Map<string, Asset> = new Map();

    constructor() {

    }


    //添加资源
    addRes(resName: string, res: Asset) {
        if (resName.length <= 0 || !res) {
            error(resName + "资源名为空或添加的资源为空");
            return;
        }
        //如果资源已经存储过了，就不需要再存储了
        if (this._mapRes.has(resName)) {
            //error(resName + "资源已经存在");
            return;
        }
        this._mapRes.set(resName, res);
        //console.log(resName + "资源已加载");
    }
    //获取资源  通过泛型确定所需要获取资源的类型
    //因为调用此获取资源的函数，所获取的资源类型是unkonwn,unknown无法直接赋值给其他变量，需要确定资源类型在赋值给其他变量，
    //所以在获取时确定资源的类型
    getRes<T>(resName: string): T {
        if (resName.length <= 0) {
            error("资源名为空");
            return;
        }
        let res = this._mapRes.get(resName);
        if (!res) {
            error(resName + "资源不存在");
            return null;
        }
        return res as T;
    }
}

//预制体管理者  存取预制体
export class PrefabMgr extends SpecialResMgr {
    constructor() {
        super();
    }
}

//精灵帧管理者  存取精灵帧
export class SpriteFrameMgr extends SpecialResMgr {
    constructor() {
        super();
    }
}

//json资源管理
export class JsonMgr extends SpecialResMgr {
    constructor() {
        super();
    }
}


//音频管理者，负责音频的存取，播放  音频包括背景音乐和音效
export class AudioMgr extends SpecialResMgr {
    //注意：音频组件是AudioSource 而音频资源是AudioClip
    private audioBgmComp: AudioSource = null;
    private audioEffectComp: AudioSource = null;
    constructor() {
        //写了extends继承基类，就需要写super();进行继承
        super();
        //进行初始化数据，如：创建节点，因为需要在创建这个对象时就创建节点，
        // 而构造函数在创建对象时就会自动被调用，故将此初始化函数写在构造函数中
        this._init();
    }
    private _init() {
        //创建一个挂载背景音乐的节点
        let audioBgmNode = new Node();
        //在节点上添加组件，因为音频需要AudioSource组件控制
        this.audioBgmComp = audioBgmNode.addComponent(AudioSource);
        //将此节点的父节点设置为场景
        audioBgmNode.parent = director.getScene();
        //并将此节点设置为常驻节点
        director.addPersistRootNode(audioBgmNode);



        //创建一个挂载音效的节点
        let audioEffectNode = new Node();
        //在节点上添加组件，因为音频需要AudioSource组件控制
        this.audioEffectComp = audioEffectNode.addComponent(AudioSource);
        //设置常驻节点：创建节点，设置节点的父节点为场景，添加为常驻节点
        //将此节点的父节点设置为当前场景
        audioEffectNode.parent = director.getScene();
        //并将此节点添加为常驻节点
        director.addPersistRootNode(audioEffectNode);
    }

    playBgm(clipName: string, loop: boolean = true, volume: number = 1) {
        let clip = this.getRes<AudioClip>(clipName);
        this.audioBgmComp.clip = clip;
        this.audioBgmComp.loop = loop;
        this.audioBgmComp.volume = volume;
        this.audioBgmComp.play();
    }
    playEffect(clipName: string, loop: boolean = false, volume: number = 1) {
        let clip = this.getRes<AudioClip>(clipName);
        this.audioEffectComp.clip = clip;
        this.audioEffectComp.loop = loop;
        this.audioEffectComp.volume = volume;
        this.audioEffectComp.play();
    }
}